home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue37 / Alfresco / SortFns.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-07-27  |  11.7 KB  |  363 lines

  1. {*********************************************************}
  2. {* SortFns                                               *}
  3. {* Copyright (c) Julian M Bucknall 1998                  *}
  4. {* All rights reserved.                                  *}
  5. {*********************************************************}
  6. {* Sort routines                                         *}
  7. {*********************************************************}
  8.  
  9. {Note: this unit is released as freeware. In other words, you are free
  10.        to use this unit in your own applications, however I retain all
  11.        copyright to the code. JMB}
  12.  
  13. unit SortFns;
  14.  
  15. interface
  16.  
  17. uses
  18.   StdCtrls,
  19.   SysUtils;
  20.  
  21. type
  22.   TSortElement = double;
  23.  
  24.   TLessFunction = function (const X, Y : TSortElement) : boolean;
  25.     {function prototype to compare two items and return true if item X
  26.      is STRICTLY LESS than item Y}
  27.  
  28. procedure BubbleSort(var aItemArray    : array of TSortElement;
  29.                          aLeft, aRight : integer;
  30.                          aLessThan     : TLessFunction);
  31.  
  32. procedure ShakerSort(var aItemArray    : array of TSortElement;
  33.                          aLeft, aRight : integer;
  34.                          aLessThan     : TLessFunction);
  35.  
  36. procedure SelectionSort(var aItemArray    : array of TSortElement;
  37.                             aLeft, aRight : integer;
  38.                             aLessThan     : TLessFunction);
  39.  
  40. procedure InsertionSort(var aItemArray    : array of TSortElement;
  41.                             aLeft, aRight : integer;
  42.                             aLessThan     : TLessFunction);
  43.  
  44. procedure ShellSort(var aItemArray    : array of TSortElement;
  45.                         aLeft, aRight : integer;
  46.                         aLessThan     : TLessFunction);
  47.  
  48. procedure QuickSort(var aItemArray    : array of TSortElement;
  49.                         aLeft, aRight : integer;
  50.                         aLessThan     : TLessFunction);
  51.  
  52. procedure UsualInsertionSort(var aItemArray    : array of TSortElement;
  53.                                  aLeft, aRight : integer;
  54.                                  aLessThan     : TLessFunction);
  55.  
  56. procedure UsualQuickSort(var aItemArray    : array of TSortElement;
  57.                              aLeft, aRight : integer;
  58.                              aLessThan     : TLessFunction);
  59.  
  60. implementation
  61.  
  62. procedure BubbleSort(var aItemArray    : array of TSortElement;
  63.                          aLeft, aRight : integer;
  64.                          aLessThan     : TLessFunction);
  65. var
  66.   i, j : integer;
  67.   Temp : TSortElement;
  68. begin
  69.   for i := aLeft to pred(aRight) do
  70.     for j := aRight downto succ(i) do
  71.       if aLessThan(aItemArray[j], aItemArray[j-1]) then begin
  72.         Temp := aItemArray[j];
  73.         aItemArray[j] := aItemArray[j-1];
  74.         aItemArray[j-1] := Temp;
  75.       end;
  76. end;
  77.  
  78. procedure ShakerSort(var aItemArray    : array of TSortElement;
  79.                          aLeft, aRight : integer;
  80.                          aLessThan     : TLessFunction);
  81. var
  82.   i : integer;
  83.   Temp : TSortElement;
  84. begin
  85.   while (aLeft < aRight) do begin
  86.     for i := aRight downto succ(aLeft) do
  87.       if aLessThan(aItemArray[i], aItemArray[i-1]) then begin
  88.         Temp := aItemArray[i];
  89.         aItemArray[i] := aItemArray[i-1];
  90.         aItemArray[i-1] := Temp;
  91.       end;
  92.     inc(aLeft);
  93.     for i := succ(aLeft) to aRight do
  94.       if aLessThan(aItemArray[i], aItemArray[i-1]) then begin
  95.         Temp := aItemArray[i];
  96.         aItemArray[i] := aItemArray[i-1];
  97.         aItemArray[i-1] := Temp;
  98.       end;
  99.     dec(aRight);
  100.   end;
  101. end;
  102.  
  103. procedure SelectionSort(var aItemArray    : array of TSortElement;
  104.                             aLeft, aRight : integer;
  105.                             aLessThan     : TLessFunction);
  106. var
  107.   i, j : integer;
  108.   IndexOfMin : integer;
  109.   Temp : TSortElement;
  110. begin
  111.   for i := aLeft to pred(aRight) do begin
  112.     IndexOfMin := i;
  113.     for j := succ(i) to aRight do
  114.       if aLessThan(aItemArray[j], aItemArray[IndexOfMin]) then
  115.         IndexOfMin := j;
  116.     Temp := aItemArray[i];
  117.     aItemArray[i] := aItemArray[IndexOfMin];
  118.     aItemArray[IndexOfMin] := Temp;
  119.   end;
  120. end;
  121.  
  122. procedure UsualInsertionSort(var aItemArray    : array of TSortElement;
  123.                                  aLeft, aRight : integer;
  124.                                  aLessThan     : TLessFunction);
  125. var
  126.   i, j : integer;
  127.   Temp : TSortElement;
  128. begin
  129.   for i := succ(aLeft) to aRight do begin
  130.     Temp := aItemArray[i];
  131.     j := i;
  132.     while (j > aLeft) and aLessThan(Temp, aItemArray[j-1]) do begin
  133.       aItemArray[j] := aItemArray[j-1];
  134.       dec(j);
  135.     end;
  136.     aItemArray[j] := Temp;
  137.   end;
  138. end;
  139.  
  140. procedure InsertionSort(var aItemArray    : array of TSortElement;
  141.                             aLeft, aRight : integer;
  142.                             aLessThan     : TLessFunction);
  143. var
  144.   i, j : integer;
  145.   IndexOfMin : integer;
  146.   Temp : TSortElement;
  147. begin
  148.   {find the smallest element and put it in the first position}
  149.   IndexOfMin := aLeft;
  150.   for i := succ(aLeft) to aRight do
  151.     if aLessThan(aItemArray[i], aItemArray[IndexOfMin]) then
  152.       IndexOfMin := i;
  153.   if (aLeft <> IndexOfMin) then begin
  154.     Temp := aItemArray[aLeft];
  155.     aItemArray[aLeft] := aItemArray[IndexOfMin];
  156.     aItemArray[IndexOfMin] := Temp;
  157.   end;
  158.   {now sort via insertion method}
  159.   for i := aLeft+2 to aRight do begin
  160.     Temp := aItemArray[i];
  161.     j := i;
  162.     while aLessThan(Temp, aItemArray[j-1]) do begin
  163.       aItemArray[j] := aItemArray[j-1];
  164.       dec(j);
  165.     end;
  166.     aItemArray[j] := Temp;
  167.   end;
  168. end;
  169.  
  170. procedure ShellSort(var aItemArray    : array of TSortElement;
  171.                         aLeft, aRight : integer;
  172.                         aLessThan     : TLessFunction);
  173. var
  174.   i, j : integer;
  175.   h    : integer;
  176.   Temp : TSortElement;
  177. begin
  178.   {firstly calculate the first h value we shall use: it'll be about
  179.    one ninth of the number of the elements}
  180.   h := 1;
  181.   while (h <= (aRight - aLeft) div 9) do
  182.     h := (h * 3) + 1;
  183.   {start a loop that'll decrement h by one third each time through}
  184.   while (h > 0) do begin
  185.     {now insertion sort each h-subfile}
  186.     for i := (aLeft + h) to aRight do begin
  187.       Temp := aItemArray[i];
  188.       j := i;
  189.       while (j >= (aLeft+h)) and aLessThan(Temp, aItemArray[j-h]) do begin
  190.         aItemArray[j] := aItemArray[j-h];
  191.         dec(j, h);
  192.       end;
  193.       aItemArray[j] := Temp;
  194.     end;
  195.     {decrease h by a third}
  196.     h := h div 3;
  197.   end;
  198. end;
  199.  
  200. procedure UsualQuickSort(var aItemArray    : array of TSortElement;
  201.                              aLeft, aRight : integer;
  202.                              aLessThan     : TLessFunction);
  203.   function Partition(L, R : integer): integer;
  204.   var
  205.     i, j : integer;
  206.     Last : TSortElement;
  207.     Temp : TSortElement;
  208.   begin
  209.     {set up the indexes}
  210.     i := L;
  211.     j := pred(R);
  212.     {get the partition element}
  213.     Last := aItemArray[R];
  214.     {do forever (we'll break out of the loop when needed)}
  215.     while true do begin
  216.       {find the first element greater than or equal to the partition
  217.        element from the left; note that our partition element will
  218.        stop this loop}
  219.       while aLessThan(aItemArray[i], Last) do
  220.         inc(i);
  221.       {find the first element less than the partition element from the
  222.        right; check to break out of the loop if we hit the left
  223.        element - we have no sentinel there}
  224.       while aLessThan(Last, aItemArray[j]) do begin
  225.         if (j = L) then
  226.           Break;
  227.         dec(j);
  228.       end;
  229.       {if we crossed get out of this infinite loop to swap the
  230.        partition element into place}
  231.       if (i >= j) then
  232.         Break;
  233.       {otherwise swap the two out-of-place elements}
  234.       Temp := aItemArray[i];
  235.       aItemArray[i] := aItemArray[j];
  236.       aItemArray[j] := Temp;
  237.       {and continue}
  238.       inc(i);
  239.       dec(j);
  240.     end;
  241.     {swap the partition element into place, return the dividing index}
  242.     aItemArray[R] := aItemArray[i];
  243.     aItemArray[i] := Last;
  244.     Result := i;
  245.   end;
  246.   procedure QuickSortPrim(L, R : integer);
  247.   var
  248.     DividingItem : integer;
  249.   begin
  250.     {stop the recursion, if needed}
  251.     if (R - L) <= 0 then
  252.       Exit;
  253.     {otherwise, partition about the final element in the set}
  254.     DividingItem := Partition(L, R);
  255.     {recursively quicksort the two subsets either side of the dividing
  256.      element}
  257.     QuicksortPrim(L, pred(DividingItem));
  258.     QuicksortPrim(succ(DividingItem), R);
  259.   end;
  260. begin
  261.   {start it all off}
  262.   QuicksortPrim(aLeft, aRight);
  263. end;
  264.  
  265. procedure QuickSort(var aItemArray    : array of TSortElement;
  266.                         aLeft, aRight : integer;
  267.                         aLessThan     : TLessFunction);
  268.   function Partition(L, R : integer): integer;
  269.   var
  270.     i, j : integer;
  271.     Last : TSortElement;
  272.     Temp : TSortElement;
  273.   begin
  274.     {set up the indexes}
  275.     i := L;
  276.     j := pred(R);
  277.     {get the partition element}
  278.     Last := aItemArray[R];
  279.     {do forever (we'll break out of the loop when needed)}
  280.     while true do begin
  281.       {find the first element greater than or equal to the partition
  282.        element from the left; note that our partition element will
  283.        stop this loop}
  284.       while aLessThan(aItemArray[i], Last) do
  285.         inc(i);
  286.       {find the first element less than the partition element from the
  287.        right; note the median-of-three algorithm has ensured we have
  288.        a sentinel on the left}
  289.       while not aLessThan(aItemArray[j], Last) do
  290.         dec(j);
  291.       {if we crossed get out of this infinite loop to swap the
  292.        partition element into place}
  293.       if (i >= j) then
  294.         Break;
  295.       {otherwise swap the two out-of-place elements}
  296.       Temp := aItemArray[i];
  297.       aItemArray[i] := aItemArray[j];
  298.       aItemArray[j] := Temp;
  299.       {and continue}
  300.       inc(i);
  301.       dec(j);
  302.     end;
  303.     {swap the partition element into place, return the dividing index}
  304.     aItemArray[R] := aItemArray[i];
  305.     aItemArray[i] := Last;
  306.     Result := i;
  307.   end;
  308.   procedure QuickSortPrim(L, R : integer);
  309.   var
  310.     DividingItem : integer;
  311.     Temp : TSortElement;
  312.     i, j : integer;
  313.   begin
  314.     {if needed, stop the recursion at the cut-off point, and insertion
  315.      sort}
  316.     if (R - L) <= 10 then begin
  317.       for i := succ(L) to R do begin
  318.         Temp := aItemArray[i];
  319.         j := i;
  320.         while (j > L) and aLessThan(Temp, aItemArray[j-1]) do begin
  321.           aItemArray[j] := aItemArray[j-1];
  322.           dec(j);
  323.         end;
  324.         aItemArray[j] := Temp;
  325.       end;
  326.       Exit;
  327.     end;
  328.     {calculate the median-of-three element; for an extra bit of speed,
  329.      put the smallest element of the three in the first position, the
  330.      greatest in the last position, and the median in the last-but-one
  331.      position and partition a smaller subset excluding the first and
  332.      last}
  333.     Temp := aItemArray[(L+R) shr 1];
  334.     aItemArray[(L+R) shr 1] := aItemArray[pred(R)];
  335.     aItemArray[pred(R)] := Temp;
  336.     if not aLessThan(aItemArray[L], aItemArray[pred(R)]) then begin
  337.       Temp := aItemArray[L];
  338.       aItemArray[L] := aItemArray[pred(R)];
  339.       aItemArray[pred(R)] := Temp;
  340.     end;
  341.     if not aLessThan(aItemArray[L], aItemArray[R]) then begin
  342.       Temp := aItemArray[L];
  343.       aItemArray[L] := aItemArray[R];
  344.       aItemArray[R] := Temp;
  345.     end;
  346.     if not aLessThan(aItemArray[pred(R)], aItemArray[R]) then begin
  347.       Temp := aItemArray[R];
  348.       aItemArray[R] := aItemArray[pred(R)];
  349.       aItemArray[pred(R)] := Temp;
  350.     end;
  351.     DividingItem := Partition(succ(L), pred(R));
  352.     {recursively quicksort the two subsets either side of the dividing
  353.      element}
  354.     QuickSortPrim(L, pred(DividingItem));
  355.     QuickSortPrim(succ(DividingItem), R);
  356.   end;
  357. begin
  358.   {start it all off}
  359.   QuickSortPrim(aLeft, aRight);
  360. end;
  361.  
  362. end.
  363.